<template>
  <el-dialog
    :title="`为 ${roleName} 分配菜单权限`"
    :visible="visible"
    :width="600"
    @close="handleClose"
  >
    <div class="content">
      <div class="mb-4">
        <el-checkbox v-model="checkAll" @change="handleCheckAllChange">全选</el-checkbox><br>
        <el-switch
          v-model="isOverride"
          class="ml-4"
          active-text="覆盖原有权限"
          inactive-text="追加权限"
        />
      </div>
      <el-tree
        ref="treeRef"
        :data="menuTree"
        :props="treeProps"
        :show-checkbox="true"
        :default-checked-keys="defaultCheckedKeys"
        node-key="id"
        highlight-current
        :expand-on-click-node="false"
        @check-change="handleCheckChange"
      />
    </div>
    <template #footer>
      <el-button @click="handleClose">取消</el-button>
      <el-button type="primary" @click="handleSubmit" :loading="loading">
        保存
      </el-button>
    </template>
  </el-dialog>
</template>

<script setup>
import { ref, computed, onMounted, nextTick, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { menuApi } from '@/api/menu.js';
import { roleApi } from '@/api/role.js';

const props = defineProps({
  roleId: {
    type: String,
    required: true
  },
  roleName: {
    type: String,
    required: true
  },
  visible: {
    type: Boolean,
    default: false
  },
  initialPermissions: {
    type: Object,
    default: () => []
  }
})

const emit = defineEmits(['updateVisible', 'success'])

const treeRef = ref(null)
const loading = ref(false)
const checkAll = ref(false)
const isOverride = ref(false) // 是否覆盖原有权限

// 树形控件配置
const treeProps = {
  children: 'children',
  label: 'name'
}

// 菜单树数据
const menuTree = ref([])

// 默认选中的菜单ID
const defaultCheckedKeys = ref([])

// 获取所有菜单ID
const getAllMenuIds = () => {
  const ids = []
  const traverse = (nodes) => {
    nodes.forEach(node => {
      ids.push(node.id)
      if (node.children && node.children.length) {
        traverse(node.children)
      }
    })
  }
  traverse(menuTree.value)
  return ids
}

// 监听弹窗显示事件，确保树组件正确初始化
const handleDialogVisibleChange = async () => {
  // 等待DOM更新完成
  await nextTick()
  try {
    // 获取菜单树数据
    const menuTreeRes = await menuApi.getMenuTree()    
    menuTree.value = menuTreeRes    
    // 从对象的 menus 属性中提取要勾选的菜单 ID，使用传递过来的初始权限
    const menus = props.initialPermissions.menus || [];    
    defaultCheckedKeys.value = menus.map(menu => menu.id) || [];    
  } catch (error) {    
    ElMessage.error(error.message || '获取菜单树或角色菜单权限失败')
  }
  // 更新全选状态
  if (treeRef.value) {
    const checkedKeys = treeRef.value.getCheckedKeys()
    const allKeys = getAllMenuIds()
    checkAll.value = checkedKeys.length === allKeys.length
  }
}

// 提交菜单权限分配
const handleSubmit = async () => {
  // 修复：确保 treeRef 已初始化
  if (!treeRef.value) {
    ElMessage.error('菜单树组件未正确加载')
    return
  }
  // 获取选择的权限
  const checkedKeys = treeRef.value.getCheckedKeys()  
  // 校验：至少选择一项菜单权限
  if (checkedKeys.length === 0) {
    ElMessage.warning('请至少选择一项菜单权限')
    return
  }
  
  loading.value = true
  try {    
    // 构造符合后端接口的数据格式
    const requestData = {
      menuIds: checkedKeys,
      isOverride: isOverride.value
    }
    
    await roleApi.assignMenuPermissions(props.roleId, requestData)    
    ElMessage.success('菜单权限分配成功')
    emit('success') // 通知父组件更新
    handleClose()
  } catch (error) {
    ElMessage.error(error.message || '菜单权限分配失败')
  } finally {
    loading.value = false
  }
}

// 全选/取消全选
const handleCheckAllChange = (value) => {
  if (treeRef.value) {
    treeRef.value.setCheckedKeys(
      value ? getAllMenuIds() : []
    )
  }
}

// 菜单勾选变化时，更新全选状态
const handleCheckChange = () => {
  if (treeRef.value) {
    const checkedKeys = treeRef.value.getCheckedKeys()
    const allKeys = getAllMenuIds()
    checkAll.value = checkedKeys.length === allKeys.length
  }
}

// 关闭弹窗
const handleClose = () => {
  emit('updateVisible', false)
}

// 监听props.visible变化
watch(() => props.visible, handleDialogVisibleChange)
// 监听 props.initialPermissions 的变化
watch(() => props.initialPermissions, (newVal, oldVal) => {
  if (newVal && newVal.menus) {
    handleDialogVisibleChange();
  }
});

// 组件挂载时初始化
onMounted(async() => {  
  handleDialogVisibleChange()
})
</script>

<style scoped>
.content {
  max-height: 60vh;
  overflow-y: auto;
}
</style>